// Created: Dec 14, 2014
//
// Author: wjinwen.1988@gmail.com

#ifndef CHI_NET_TCPCLIENT_H
#define CHI_NET_TCPCLIENT_H

#include <stdint.h>
#include <memory>

#include "chi/mutex.h"
#include "chi/net/tcpconnection.h"

namespace chi {
namespace net {

class Connector;
typedef std::shared_ptr<Connector> ConnectorPtr;

// TcpClient作为一个TCP客户端，可自动管理与远程服务器
// 建立的TCP连接，通过注册的回调函数，把TCP连接上产生
// 的事件（比如可读、可写等）告诉外部用户。
// Example Usage:
//   //定义一个TcpClient对象
//   TcpClient* tcpclient = new TcpClient(loop,        // 事件管理EventLoop对象指针
//                                        server_addr, // 服务器地址
//                                        service_name // 服务名称
//                                        ); 
//    // 注册回调函数
//    tcpclient->set_message_callback(std::bind(OnMessage, _1, _2));
//    // 开始连接
//    tcpclient->Connet();
//
//    // 实现接收消息的回调函数OnMessage
//    void OnMessage(TcpConnection* conn, Buffer* message) {
//      std::cout << message->Peek() << std::endl;
//    }
class TcpClient
{
 public:
  TcpClient(EventLoop* loop, 
            const InetAddress& server_addr,
            const std::string& name);
  ~TcpClient();
  
  // 禁止拷贝
  TcpClient(const TcpClient&) = delete;
  void operator=(const TcpClient&) = delete;

  // 连接服务器
  void Connect();
  // 断开连接
  void Disconnect();
  // 关闭TCP客户端
  void Stop();

  TcpConnectionPtr connection() const { return connection_; }
  EventLoop* loop() const { return loop_; }
  bool retry() const { return retry_; }
  // 打开自动重连
  void EnableRetry() { retry_ = true; }

  // 设置连接变化回调函数
  void set_connection_callback(const ConnectionCallback& cb);
  // 设置消息达到回调函数
  void set_message_callback(const MessageCallback& cb);
 private:
  // 非线程安全，只在loop内调用。
  void NewConnection(int sockfd);
  // 删除连接
  // 非线程安全，只在loop内调用。
  void RemoveConnection(const TcpConnectionPtr& conn);

  EventLoop* loop_;         // 用于事件管理
  ConnectorPtr connector_;  // 用于连接管理
  const std::string name_;  // 服务名
  // 连接变化回调函数
  ConnectionCallback connection_cb_;
  // 消息达到回调函数
  MessageCallback message_cb_;
  // 连接失败或连接断开，是否重试？
  bool retry_;
  // 是否连接成功？
  bool connect_;
  // 下一连接id，用于生成连接名。
  int next_connid_;
  mutable MutexLock mutex_;
  TcpConnectionPtr connection_;
};

}
}
#endif 
